﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Runtime.Remoting;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
using GurLoader;
using GurLoader.Service;
using GurLoader.Service.ImgurTaskBuilder;
using GurLoader.Util;
using GurLoader.ViewModel;
using Imgur.Net;
using Moq;
using NUnit.Framework;

namespace GurLoaderWPF.Test.ViewModel
{
    [TestFixture]
    public class GurLoaderViewModelTests
    {

        [Test]
        public void CreateInstanceTest()
        {
            Mock<Progress<IDelegatingCommandProgress>> progressMock = new Mock<Progress<IDelegatingCommandProgress>>();
            Mock<CancellationTokenSource> cancelMock = new Mock<CancellationTokenSource>();
            Mock<ICommandManager> mockCommandManager = new Mock<ICommandManager>();

            GurLoaderViewModel vm = new GurLoaderViewModel(progressMock.Object, cancelMock.Object, mockCommandManager.Object);

            Assert.IsNotNull(vm);
        }

        [Test]
        [ExpectedException(typeof(ArgumentNullException))]
        public void CreateInstanceNullProgressTest()
        {
            Mock<CancellationTokenSource> cancelMock = new Mock<CancellationTokenSource>();
            Mock<ICommandManager> mockCommandManager = new Mock<ICommandManager>();

            GurLoaderViewModel vm = new GurLoaderViewModel(null, cancelMock.Object, mockCommandManager.Object);
        }

        [Test]
        [ExpectedException(typeof(ArgumentNullException))]
        public void CreateInstanceNullCancellTokenTest()
        {
            Mock<Progress<IDelegatingCommandProgress>> progressMock = new Mock<Progress<IDelegatingCommandProgress>>();
            Mock<ICommandManager> mockCommandManager = new Mock<ICommandManager>();

            GurLoaderViewModel vm = new GurLoaderViewModel(progressMock.Object, null, mockCommandManager.Object);
        }

        [Test]
        [ExpectedException(typeof(ArgumentNullException))]
        public void CreateInstanceNullCommandManagerTest()
        {
            Mock<Progress<IDelegatingCommandProgress>> progressMock = new Mock<Progress<IDelegatingCommandProgress>>();
            Mock<CancellationTokenSource> cancelMock = new Mock<CancellationTokenSource>();

            GurLoaderViewModel vm = new GurLoaderViewModel(progressMock.Object, cancelMock.Object, null);
        }

        [Test]
        public void CommandProgressChangeEventRaisedTest()
        {
            Mock<Progress<IDelegatingCommandProgress>> progressMock = new Mock<Progress<IDelegatingCommandProgress>>();
            Mock<CancellationTokenSource> cancelMock = new Mock<CancellationTokenSource>();
            Mock<IDispatcher> mockDispatcher = new Mock<IDispatcher>();
            Mock<ICommandManager> mockCommandManager = new Mock<ICommandManager>();

            GurLoaderViewModel vm = new GurLoaderViewModel(progressMock.Object, cancelMock.Object, mockCommandManager.Object);

            string propertyChangedName = string.Empty;
            string expectedPropertyName = "CommandProgress";

            vm.PropertyChanged += (sender, e) =>
            {
                if (! expectedPropertyName.Equals(e.PropertyName))
                    Assert.Fail("Unknown property change event called.");

                propertyChangedName = e.PropertyName;
            };

            vm.CommandProgress = new DelegatingCommandProgress(Command.SendAlbum, 10, string.Empty, mockDispatcher.Object);

            cancelMock.VerifyAll();
            progressMock.VerifyAll();
            mockCommandManager.VerifyAll();
            
            Assert.AreEqual(expectedPropertyName, propertyChangedName);
        }

        [Test]
        public void RequestCancelCommandSuccess()
        {
            Mock<Progress<IDelegatingCommandProgress>> progressMock = new Mock<Progress<IDelegatingCommandProgress>>();
            
            CancellationTokenSource cts = new CancellationTokenSource();
            Mock<ICommandManager> mockCommandManager = new Mock<ICommandManager>();

            GurLoaderViewModel vm = new GurLoaderViewModel(progressMock.Object, cts, mockCommandManager.Object);
            vm.RequestCancelCommand.Execute(null);

            Assert.IsTrue(cts.IsCancellationRequested);
            progressMock.VerifyAll();
            mockCommandManager.VerifyAll();
        }

        [Test]
        public void RequestCancelCommandCanCancelTest()
        {
            Progress<IDelegatingCommandProgress> progress = new Progress<IDelegatingCommandProgress>();
            Mock<IDelegatingCommandProgress> mockProgressReport = new Mock<IDelegatingCommandProgress>();
            Mock<ICommandManager> mockCommandManager = new Mock<ICommandManager>();

            mockProgressReport.Setup(x => x.IsTotalProgressComplete).Returns(false).Verifiable();

            CancellationTokenSource cts = new CancellationTokenSource();
            GurLoaderViewModel vm = new GurLoaderViewModel(progress, cts, mockCommandManager.Object);

            ManualResetEvent mre = new ManualResetEvent(false);
            vm.PropertyChanged += (sender, e) =>
            {
                if (e.PropertyName.Equals("CommandProgress"))
                    mre.Set();
            };

            ((IProgress<IDelegatingCommandProgress>)progress).Report(mockProgressReport.Object);

            mre.WaitOne();

            Assert.IsTrue(vm.RequestCancelCommand.CanExecute(null));
            mockProgressReport.VerifyAll();
            mockCommandManager.VerifyAll();
        }

        [Test]
        public void RequestCancelCommandCancellationPreviouslyRequestedTest()
        {
            Progress<IDelegatingCommandProgress> progress = new Progress<IDelegatingCommandProgress>();
            Mock<IDelegatingCommandProgress> mockProgressReport = new Mock<IDelegatingCommandProgress>();
            Mock<ICommandManager> mockCommandManager = new Mock<ICommandManager>();

            CancellationTokenSource cts = new CancellationTokenSource();
            cts.Cancel();
            GurLoaderViewModel vm = new GurLoaderViewModel(progress, cts, mockCommandManager.Object);

            ((IProgress<IDelegatingCommandProgress>)progress).Report(mockProgressReport.Object);

            Assert.IsFalse(vm.RequestCancelCommand.CanExecute(null));
            mockProgressReport.VerifyAll();
            mockCommandManager.VerifyAll();
        }

        [Test]
        public void RequestCancelCommandNullProgressTest()
        {
            Progress<IDelegatingCommandProgress> progress = new Progress<IDelegatingCommandProgress>();
            Mock<IDelegatingCommandProgress> mockProgressReport = new Mock<IDelegatingCommandProgress>();
            Mock<ICommandManager> mockCommandManager = new Mock<ICommandManager>();

            CancellationTokenSource cts = new CancellationTokenSource();
            GurLoaderViewModel vm = new GurLoaderViewModel(progress, cts, mockCommandManager.Object);

            Assert.IsFalse(vm.RequestCancelCommand.CanExecute(null));
            mockProgressReport.VerifyAll();
            mockCommandManager.VerifyAll();
        }

        [Test]
        public void RequestCancelCommandAlreadyCompletedActionTest()
        {
            Progress<IDelegatingCommandProgress> progress = new Progress<IDelegatingCommandProgress>();
            Mock<IDelegatingCommandProgress> mockProgressReport = new Mock<IDelegatingCommandProgress>();
            Mock<ICommandManager> mockCommandManager = new Mock<ICommandManager>();

            mockProgressReport.Setup(x=>x.IsTotalProgressComplete).Returns(true).Verifiable();

            CancellationTokenSource cts = new CancellationTokenSource();
            GurLoaderViewModel vm = new GurLoaderViewModel(progress, cts, mockCommandManager.Object);

            ((IProgress<IDelegatingCommandProgress>)progress).Report(mockProgressReport.Object);

            Assert.IsFalse(vm.RequestCancelCommand.CanExecute(null));
            mockProgressReport.VerifyAll();
            mockCommandManager.VerifyAll();
        }

        [Test]
        public void BrowserOpenItemLinkNullProgressTest()
        {
            Progress<IDelegatingCommandProgress> progress = new Progress<IDelegatingCommandProgress>();
            Mock<IDelegatingCommandProgress> mockProgressReport = new Mock<IDelegatingCommandProgress>();
            Mock<ICommandManager> mockCommandManager = new Mock<ICommandManager>();

            CancellationTokenSource cts = new CancellationTokenSource();
            GurLoaderViewModel vm = new GurLoaderViewModel(progress, cts, mockCommandManager.Object);

            Assert.IsFalse(vm.BrowserOpenItemLinkCommand.CanExecute(null));
            mockProgressReport.VerifyAll();
            mockCommandManager.VerifyAll();
        }

        [Test]
        public void BrowserOpenItemLinkNotCompleteActionTest()
        {
            Progress<IDelegatingCommandProgress> progress = new Progress<IDelegatingCommandProgress>();
            Mock<IDelegatingCommandProgress> mockProgressReport = new Mock<IDelegatingCommandProgress>();
            Mock<ICommandManager> mockCommandManager = new Mock<ICommandManager>();

            mockProgressReport.Setup(x => x.IsComplete).Returns(false).Verifiable();

            CancellationTokenSource cts = new CancellationTokenSource();
            GurLoaderViewModel vm = new GurLoaderViewModel(progress, cts, mockCommandManager.Object);

            ((IProgress<IDelegatingCommandProgress>)progress).Report(mockProgressReport.Object);

            Assert.IsFalse(vm.BrowserOpenItemLinkCommand.CanExecute(mockProgressReport.Object));
            mockProgressReport.VerifyAll();
            mockCommandManager.VerifyAll();
        }

        [Test]
        public void BrowserOpenItemLinkCanExecuteTest()
        {
            Progress<IDelegatingCommandProgress> progress = new Progress<IDelegatingCommandProgress>();
            Mock<IDelegatingCommandProgress> mockProgressReport = new Mock<IDelegatingCommandProgress>();
            Mock<ICommandManager> mockCommandManager = new Mock<ICommandManager>();

            mockProgressReport.Setup(x => x.IsComplete).Returns(true).Verifiable();

            CancellationTokenSource cts = new CancellationTokenSource();
            GurLoaderViewModel vm = new GurLoaderViewModel(progress, cts, mockCommandManager.Object);

            ((IProgress<IDelegatingCommandProgress>)progress).Report(mockProgressReport.Object);

            Assert.IsTrue(vm.BrowserOpenItemLinkCommand.CanExecute(mockProgressReport.Object));
            mockProgressReport.VerifyAll();
            mockCommandManager.VerifyAll();
        }

        [Test]
        public void ClipboardCopyItemNullProgressTest()
        {
            Progress<IDelegatingCommandProgress> progress = new Progress<IDelegatingCommandProgress>();
            Mock<IDelegatingCommandProgress> mockProgressReport = new Mock<IDelegatingCommandProgress>();
            Mock<ICommandManager> mockCommandManager = new Mock<ICommandManager>();

            CancellationTokenSource cts = new CancellationTokenSource();
            GurLoaderViewModel vm = new GurLoaderViewModel(progress, cts, mockCommandManager.Object);

            Assert.IsFalse(vm.ClipboardCopyItemLinkCommand.CanExecute(null));
            mockProgressReport.VerifyAll();
            mockCommandManager.VerifyAll();
        }

        [Test]
        public void ClipboardCopyItemNotCompleteActiontest()
        {
            Progress<IDelegatingCommandProgress> progress = new Progress<IDelegatingCommandProgress>();
            Mock<IDelegatingCommandProgress> mockProgressReport = new Mock<IDelegatingCommandProgress>();
            Mock<ICommandManager> mockCommandManager = new Mock<ICommandManager>();

            mockProgressReport.Setup(x => x.IsComplete).Returns(false).Verifiable();

            CancellationTokenSource cts = new CancellationTokenSource();
            GurLoaderViewModel vm = new GurLoaderViewModel(progress, cts, mockCommandManager.Object);

            ((IProgress<IDelegatingCommandProgress>)progress).Report(mockProgressReport.Object);

            Assert.IsFalse(vm.ClipboardCopyItemLinkCommand.CanExecute(mockProgressReport.Object));
            mockProgressReport.VerifyAll();
            mockCommandManager.VerifyAll();
        }

        [Test]
        public void ClipboardCopyItemCanExecuteTest()
        {
            Progress<IDelegatingCommandProgress> progress = new Progress<IDelegatingCommandProgress>();
            Mock<IDelegatingCommandProgress> mockProgressReport = new Mock<IDelegatingCommandProgress>();
            Mock<ICommandManager> mockCommandManager = new Mock<ICommandManager>();

            mockProgressReport.Setup(x => x.IsComplete).Returns(true).Verifiable();

            CancellationTokenSource cts = new CancellationTokenSource();
            GurLoaderViewModel vm = new GurLoaderViewModel(progress, cts, mockCommandManager.Object);

            ((IProgress<IDelegatingCommandProgress>)progress).Report(mockProgressReport.Object);

            Assert.IsTrue(vm.ClipboardCopyItemLinkCommand.CanExecute(mockProgressReport.Object));
            mockProgressReport.VerifyAll();
            mockCommandManager.VerifyAll();
        }

        [Test, RequiresSTA]
        public void ClipboardCopyItemSuccessTest()
        {
            Progress<IDelegatingCommandProgress> progress = new Progress<IDelegatingCommandProgress>();
            Mock<ICommandManager> mockCommandManager = new Mock<ICommandManager>();

            string testAlbumId = "abcde";
            string testAlbumIdLink = "http://imgur.com/a/" + testAlbumId;

            AlbumInfo albumInfo = new AlbumInfo(testAlbumId, string.Empty, string.Empty, DateTime.Now, LayoutStyle.Blog,
                0, testAlbumIdLink, string.Empty);

            AlbumUploadResult albumUploadResult = new AlbumUploadResult(albumInfo);
            CommandProgress cp = new CommandProgress(Command.SendAlbum, string.Empty, albumUploadResult);
            CancellationTokenSource cts = new CancellationTokenSource();

            GurLoaderViewModel vm = new GurLoaderViewModel(progress, cts, mockCommandManager.Object);

            vm.ClipboardCopyItemLinkCommand.Execute(cp);

            Assert.AreEqual( testAlbumIdLink, Clipboard.GetText() );
            mockCommandManager.VerifyAll();
        }
    }
}
